package com.thinkgem.jeesite.modules.data.rep.web;

import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.utils.DateUtils;
import com.thinkgem.jeesite.modules.data.rep.entity.ReportDownLoad;
import com.thinkgem.jeesite.modules.data.rep.entity.TfEcReportConfig;
import com.thinkgem.jeesite.modules.data.rep.entity.TfEcReportConfigIn;
import com.thinkgem.jeesite.modules.data.rep.entity.TfEcReportConfigOut;
import com.thinkgem.jeesite.modules.data.rep.service.ReportConfService;
import com.thinkgem.jeesite.modules.data.rep.utils.ExportExcelUtil;
import com.thinkgem.jeesite.modules.sys.entity.Dict;
import com.thinkgem.jeesite.modules.sys.entity.User;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;
import org.activiti.engine.impl.util.json.JSONArray;
import org.activiti.engine.impl.util.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报表生成controller
 *
 * @Author Havel
 */
@Controller
@RequestMapping(value = "${adminPath}/report/produce")
public class ReportProduceController extends ReportConfBaseController {
    private static Logger logger = LoggerFactory.getLogger(ReportProduceController.class);

    @Autowired
    ReportConfService reportConfService;

    /**
     * 报表内容列表
     */
    @RequestMapping(value = {"list", ""})
    @RequiresPermissions("report:conf:reportList")
    public String list(@RequestParam long reportId, HttpServletRequest request, HttpServletResponse response, Model model) {
        TfEcReportConfig report = reportConfService.getConfigById(reportId);
        if (report == null) {
            throw new NullPointerException("没有此报表");
        }
        reportConfig = report;
        if (!secondGradePermissionVerify()) {
            throw new RuntimeException("没有访问报表数据的权限，请联系统管理员");
        }

        //User currentUser = UserUtils.getUser();
        //report.setCurrentUser(currentUser);
        TfEcReportConfigIn configIn = new TfEcReportConfigIn();
        configIn.setReportId(reportId);
        List<TfEcReportConfigIn> reportIns = reportConfService.findList(configIn);
        report.setReportConfigIns(reportIns);
        List<Dict> selectList = null;
        if (reportIns != null && reportIns.size() != 0) {
            for (TfEcReportConfigIn reportIn : reportIns) {
                String param = request.getParameter(reportIn.getItemCode());
                if (StringUtils.isNotBlank(param)) {
                    reportIn.setParamValue(param);
                } else {
                    if (StringUtils.isNotBlank(reportIn.getInitialValue())) {
                        reportIn.setParamValue(reportIn.getInitialValue());
                    }
                }

                switch (reportIn.getItemType()) {
                    case TfEcReportConfigIn.ITEM_TYPE_MENU:
                        if (StringUtils.isNotBlank(reportIn.getCheckType())) {
                            selectList = new ArrayList<Dict>();
                            String[] strs = reportIn.getCheckType().split(";");
                            for (int i = 0; i < strs.length; i++) {
                                Dict dict = new Dict();
                                String str[] = strs[i].split(",");
                                dict.setValue(str[0]);
                                dict.setLabel(str[1]);
                                selectList.add(dict);
                            }
                        }
                        break;
                    case TfEcReportConfigIn.ITEM_TYPE_DICT:
                        selectList = DictUtils.getDictList(reportIn.getCheckType());
                        break;
                    case TfEcReportConfigIn.ITEM_TYPE_SQL:
                        selectList = reportConfService.findSelectList(reportIn.getCheckType());
                        break;
                }
                reportIn.setSelectList(selectList);
            }
        }

        //查询报表
        TfEcReportConfigOut configOut = new TfEcReportConfigOut();
        configOut.setReportId(reportId);
        configOut.setSpanType(null);
        List<TfEcReportConfigOut> allOut = reportConfService.findList(configOut);
        List<TfEcReportConfigOut> out0 = new ArrayList<>();
        List<TfEcReportConfigOut> out1 = new ArrayList<>();
        List<TfEcReportConfigOut> out2 = new ArrayList<>();
        List<TfEcReportConfigOut> out01 = new ArrayList<>();
        for (TfEcReportConfigOut out : allOut) {
            switch (out.getSpanType()) {
                case "0":
                    out0.add(out);
                    out01.add(out);
                    break;
                case "1":
                    out1.add(out);
                    out01.add(out);
                    break;
                case "2":
                    out2.add(out);
                    break;
            }
        }

        report.setReportConfigOuts(out01);
        Page<TfEcReportConfig> page = report.getPage();
        page.setPageNo(getPageNo(request, response));
        page.setPageSize(getPageSize(request, response, 10));
        page = reportConfService.findResultListPage(page, report, "");
        model.addAttribute("page", page);

        model.addAttribute("out0", out0);
        model.addAttribute("out1", out1);
        model.addAttribute("out2", out2);
        model.addAttribute("report", report);

        return "modules/data/rep/reportProduce";
    }

    /**
     * 图形化界面报表
     */
    @RequestMapping(value = "img")
    public String getImgData(@RequestParam long reportId, HttpServletRequest request, HttpServletResponse response, Model model) throws ParseException {
        //logger.info("==Havel==>" + JSONObject.toJSONString(request.getParameterMap()));
        getReportForTableAndImg(reportId,request,response,model);
        return "modules/data/rep/reportImg";
    }


    /**
     * 同步导出报表
     * 优化：导出成功，将提示信息返回页面
     */
    @RequestMapping(value = "export")
    @RequiresPermissions("report:conf:reportExport")
    public String exportFile(@RequestParam long reportId, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
        final TfEcReportConfig report = reportConfService.getConfigById(reportId);
        if (report == null) {
            throw new NullPointerException("没有此报表");
        }
        reportConfig = report;
        if (!secondGradePermissionVerify()) {
            throw new RuntimeException("没有访问报表数据的权限，请联系统管理员");
        }

        TfEcReportConfigIn configIn = new TfEcReportConfigIn();
        configIn.setReportId(reportId);
        try {
            String fileName = report.getReportName() + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
            List<TfEcReportConfigIn> reportIns = reportConfService.findList(configIn);
            report.setReportConfigIns(reportIns);
            if (reportIns != null && reportIns.size() != 0) {
                for (TfEcReportConfigIn reportIn : reportIns) {
                    String param = request.getParameter(reportIn.getItemCode());
                    if (!StringUtils.isEmpty(param)) {
                        reportIn.setParamValue(param);//保存界面获取的参数值
                    } else {
                        if (!StringUtils.isEmpty(reportIn.getInitialValue())) {
                            reportIn.setParamValue(param);
                        }
                    }
                }
            }
            TfEcReportConfigOut configOut = new TfEcReportConfigOut();
            configOut.setReportId(reportId);
            report.setReportConfigOuts(reportConfService.findList(configOut));
            //Excel 2003及以下的版本。一张表最大支持65536行数据，256列
            //Excel 2007-2010版本。一张表最大支持1048576行，16384列
            //if (reportConfService.findCount(report, null) > 65536) {
            //    addMessage(redirectAttributes, "最多只能导出65536条数据");
            //    return "redirect:" + adminPath + "/report/produce/list?reportId=" + reportId;
            //}
            String isExportAsyn = request.getParameter("isExportAsyn");
            String dbIsExportAsyn = report.getIsExportAsyn();
            boolean exportFlag = !StringUtils.isEmpty(dbIsExportAsyn) && !StringUtils.isEmpty(isExportAsyn);

            //异步导出
            if (exportFlag && "1".equals(isExportAsyn) && ("1".equals(dbIsExportAsyn) || "2".equals(dbIsExportAsyn))) {

                // 设置查询
                final User user = UserUtils.getUser();
                final ReportDownLoad reportDownLoad = new ReportDownLoad();
                reportDownLoad.setUserId(user.getId());
                reportDownLoad.setReportName(fileName);
                reportDownLoad.setStatus((short) 0);
                Page page1 = reportConfService.findPage(reportDownLoad);
                if (page1.getList().size() > 0) {
                    addMessage(redirectAttributes, "您当前导出的报表已有任务在运行,请到报表任务列表中查看。");
                    return "redirect:" + adminPath + "/report/produce/list?reportId=" + reportId;
                }
                //保存任务
                ExportExcelUtil.saveReportDownLoad(reportDownLoad, user, report.getReportName());

                ExportReportExcel.executorService.execute(new Runnable() {
                    public void run() {
                        final long timeLog = System.currentTimeMillis();
                        final String phone = UserUtils.getUser().getMobile();
                        final String outFilePath = System.getProperty("java.io.tmpdir") + "/" + timeLog + "_" + phone + ".xlsx";
                        final File outFile = new File(outFilePath);
                        FileOutputStream outputStream = null;
                        try {
                            outputStream = new FileOutputStream(outFile);
                            ExportReportExcel exportExcel = new ExportReportExcel(report);
                            //ExportExcel exportExcel = new ExportExcel(t.getReportName(), t.getClass());
                            // 设置分页数据
                            final Page<TfEcReportConfig> condPage = report.getPage();
                            condPage.setPageNo(1);
                            condPage.setPageSize(30000);
                            report.setPage(condPage);

                            final List<Map<String, Object>> resultList = reportConfService.findResultList(report, null);
                            exportExcel.setDataList(resultList);
                            resultList.clear();
                            long listCount = resultList.size();//总数
                            int queryPageNo = (int) (listCount / 30000 + 1);//计算页数
                            for (int i = 2; i <= queryPageNo; i++) {
                                condPage.setPageNo(i);
                                report.setPage(condPage);
                                final List<Map<String, Object>> resultPage1 = reportConfService.findResultList(report, null);
                                exportExcel.setDataList(resultPage1);
                                resultPage1.clear();
                            }
                            exportExcel.write(outputStream);
                            exportExcel.dispose();
                            ExportExcelUtil.uploadFile(report.getReportName() + timeLog, reportDownLoad, outFilePath);
                        } catch (Exception e) {
                            ExportExcelUtil.updateFailReportDownLoad(reportDownLoad);
                            e.printStackTrace();
                        } finally {
                            if (outputStream != null) {
                                try {
                                    outputStream.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                            outFile.delete();
                        }
                    }
                });
            }
            //同步导出
            else if (exportFlag && "0".equals(isExportAsyn) && ("0".equals(dbIsExportAsyn) || "2".equals(dbIsExportAsyn))) {
                List<Map<String, Object>> resultList = reportConfService.findResultList(report, null);
                new ExportReportExcel(report).setDataList(resultList).write(response, fileName).dispose();
            } else {
                addMessage(redirectAttributes, "提交参数非法");
            }
        } catch (Exception e) {
            addMessage(redirectAttributes, "导出报表失败！失败信息：" + e.getMessage().substring(1, 50));
            e.printStackTrace();
        }
        addMessage(redirectAttributes, "已调用异步导出，请查看导出列表");
        return "redirect:" + adminPath + "/reportDownLoad/reportTaskList";
        //return "redirect:" + adminPath + "/report/produce/list?reportId=" + reportId;
    }

    /**
     * 异步导出报表形式
     */
    @RequestMapping(value = "/getSelectList", method = RequestMethod.POST)
    @ResponseBody
    public String getSelectList(String data, String value) {
        String replaceAll = data.replace("#{val}", "'" + value + "'");
        List<Dict> selectList = reportConfService.findSelectList(replaceAll);
        List<Map> list = new ArrayList<Map>();
        Map<String, String> res = null;
        for (int i = 0; i < selectList.size(); i++) {
            res = new HashMap();
            res.put("label", selectList.get(i).getLabel());
            res.put("value", selectList.get(i).getValue());
            list.add(res);
        }
        String jsonString = null;//JSONArray.toJSONString(list); TODO
        return jsonString;
    }
}

